package com.woniu34.order.service.impl;

import com.woniu.cinema.api.CinemaFeignApi;
import com.woniu.cinema.domain.HallMovie;
import com.woniu.common.constant.Constants;
import com.woniu.common.enums.ExceptionCode;
import com.woniu.common.exception.CustomException;
import com.woniu34.order.domain.Order;
import com.woniu34.order.domain.OrderSeat;
import com.woniu34.order.domain.request.OrderRequest;
import com.woniu34.order.mapper.OrderMapper;
import com.woniu34.order.mapper.OrderSeatMapper;
import com.woniu34.order.service.OrderService;
import io.seata.spring.annotation.GlobalTransactional;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.rabbit.annotation.Exchange;
import org.springframework.amqp.rabbit.annotation.Queue;
import org.springframework.amqp.rabbit.annotation.QueueBinding;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Service
public class OrderServiceImpl implements OrderService {

    private static final Logger logger = LoggerFactory.getLogger(OrderServiceImpl.class);
    @Autowired
    private OrderMapper orderMapper;

    @Autowired
    private OrderSeatMapper orderSeatMapper;


    @Autowired
    private CinemaFeignApi cinemaFeignApi;

    @Autowired
    private RabbitTemplate rabbitTemplate;



    @Override
    @GlobalTransactional
    public void makeOrder(OrderRequest orderRequest) {
        Long userId = getUserId();
        //0.根据hallMovieId查询票价
        HallMovie hallMovie = cinemaFeignApi.queryHallMovieById(orderRequest.getHallMovieId());
        Long fareMoney = hallMovie.getFareMoney();
        //计算订单总金额
        Long totalPay=orderRequest.getSeatIdList().size()*fareMoney;

        //1.修改座位状态(返回更新的条数)
         Integer updateCount = cinemaFeignApi.updateBatchSeatStatus(orderRequest.getSeatIdList());
        if(updateCount<orderRequest.getSeatIdList().size()){
            throw new CustomException(ExceptionCode.ORDER_FAIL);
        }

        //2.创建一个订单
        Order order = new Order();
        order.setOrderId(orderRequest.getOrderId());
        order.setOrderStatus(1);
        order.setOrderTotalDiscount(0);
        order.setOrderTotalPay(totalPay);
        order.setOrderTotal(totalPay);
        order.setOrderCount(orderRequest.getSeatIdList().size());
        order.setOrderTime(new Date());
        order.setFareMoney(fareMoney);
        order.setHallMovieId(orderRequest.getHallMovieId());
        order.setMovieId(orderRequest.getMovieId());
        order.setCinemaId(orderRequest.getCinemaId());
        order.setUserId(userId);

        orderMapper.insert(order);

        //3.订单详情
        for (Long seatId : orderRequest.getSeatIdList()) {
            OrderSeat orderSeat = new OrderSeat();
            orderSeat.setOrderId(orderRequest.getOrderId());
            orderSeat.setSeatId(seatId);
            orderSeatMapper.insert(orderSeat);
        }

        Map<String,Long> msg = new HashMap();
        msg.put("orderId",orderRequest.getOrderId());
        //发消息给rabbitmq 延时队列，5分钟用户不付款，则自动取消订单
        rabbitTemplate.convertAndSend(Constants.MQ_ORDER_DELAY_EXCHANGE_300S,Constants.MQ_ORDER_DELAY_ROUTING_KEY_300S,msg);

    }

    @Override
    public Order queryById(Long orderId) {
        return orderMapper.selectByPrimaryKey(orderId);

    }

    private Long getUserId() {
        ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = requestAttributes.getRequest();
        String useridStr = request.getHeader("userid");
        Long userId = Long.valueOf(useridStr);
        return userId;
    }


    @RabbitListener(queues = {Constants.MQ_ORDER_DLX_QUEUE_300S})
    @GlobalTransactional
    public void processExpiredOrder(Map<String,Long> msg){
        Long orderId = msg.get("orderId");

        //1.根据订单id查询seat列表
        OrderSeat orderSeat = new OrderSeat();
        orderSeat.setOrderId(orderId);
        List<Long> seatIdList = orderSeatMapper.select(orderSeat)
                .stream().map(s -> s.getSeatId()).collect(Collectors.toList());

        //2.把座位状态恢复成可出售
        Integer updateCount =  cinemaFeignApi.revertBatchSeatStatus(seatIdList);
        if(seatIdList.size()>updateCount){
            logger.error("订单失效异常：座位状态异常");
        }

        //3.删除订单详情表
        OrderSeat orderSeat1 = new OrderSeat();
        orderSeat1.setOrderId(orderId);
        orderSeatMapper.delete(orderSeat1);

        //4.修改订单状态
        orderMapper.invalidateOrder(orderId);


    }


    @RabbitListener(
            bindings = {
                    @QueueBinding(
                            value = @Queue(name = Constants.MQ_ORDER_PAY_QUEUE_NAME,
                                           durable = "true"),
                            exchange = @Exchange(name = Constants.MQ_ORDER_PAY_EXCHANGE_NAME),
                            key = {Constants.MQ_ORDER_PAY_ROUTING_KEY}
                    )
            }
    )
    public void listenCollection(Map<String,Long> msg ) {
        Long orderId = msg.get("orderId");
        int updateCount = orderMapper.updateOrderStatus2Paid(orderId);
        if(updateCount==0){
            logger.error("订单状态已失效，需要退款，orderId：{}",orderId);

            Map<String,Long> backMsg = new HashMap<>();
            backMsg.put("orderId",orderId);
            rabbitTemplate.convertAndSend(Constants.MQ_ORDER_PAY_BACK_EXCHANGE_NAME,Constants.MQ_ORDER_PAY_BACK_ROUTING_KEY,backMsg);
        }

    }

}
